package com.android.fragmentdemo.fragments
import androidx.lifecycle.ViewModelProvider
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import com.android.fragmentdemo.ApkInstallActivity
import com.android.fragmentdemo.DrawBmpViewActivity
import com.android.fragmentdemo.R
import com.android.fragmentdemo.RoomDataBaseUseActivity
import com.android.fragmentdemo.RxJavaCaseActivity
import com.android.fragmentdemo.WebViewPdfActivity
import com.android.fragmentdemo.WindowManagerShowViewActivity
import com.android.fragmentdemo.adapters.FloatRvAdapter
import com.hengfoxwolf.commonbase.base.BaseFragment
import com.android.fragmentdemo.databeans.DataFactoryIp
import com.android.fragmentdemo.databinding.FragmentMineBinding
import com.android.fragmentdemo.defineviews.FloatItemDecoration
import com.android.fragmentdemo.startActivity
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import com.hengfoxwolf.commonbase.base.adapter.BaseRvAdapter

class MineFragment : BaseFragment<FragmentMineBinding>(),CoroutineScope by MainScope() {

    private lateinit var viewModel: MineViewModel

    private lateinit var mInteractionModel: FragmentsInteractionModel

    override fun getLayoutId() = R.layout.fragment_mine

    override fun init(savedInstanceState: Bundle?) {
        //arguments.let {
        //    val title = it?.getString(KEY_PARAM) ?: ""
        //    mBinding.tvMine.text = title
        //}
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = ViewModelProvider(this)[MineViewModel::class.java]

        //ViewModel共用一个ViewModelStoreOwner实例实现共享数据
        mInteractionModel =
            ViewModelProvider(requireActivity())[FragmentsInteractionModel::class.java]

        Log.d(TAG,"${TAG}---${mInteractionModel.number.value}")

        viewModel.updateValue(10)
        viewModel.mLiveDataMap.observe(viewLifecycleOwner) {
            Log.d(TAG,"${TAG}---$it")
        }

        viewModel.updateValue0("00000")
        viewModel.updateValue1("11111")
        viewModel.updateSwitchValue(true)
        viewModel.mLiveDataSwitchMap.observe(viewLifecycleOwner) {
            Log.d(TAG,"${TAG}---$it")
        }

        viewModel.updateMediatorValue("livedata4","this is a livedata4")
        viewModel.mMediatorLiveData.observe(viewLifecycleOwner) {
            Log.d(TAG,"${TAG}---$it")
        }

        //testCoroutineStart()

        //testCoroutineDispatchers()

        //testCoroutineScope()

        //testCoroutineContext()

        testSupervisorJob()

        val mAdapter = FloatRvAdapter()
        mAdapter.setItemDataSet(DataFactoryIp.createSimpleItemData(65))
        mAdapter.setOnItemClickListener(object : BaseRvAdapter.IOnItemClickListener<String> {
            override fun onItemClick(dataItem: String, position: Int, viewId: Int) {
                when (position) {
                    0 -> {
                        mContext.startActivity<ApkInstallActivity>()
                    }
                    1 -> {
                        mContext.startActivity<RxJavaCaseActivity>()
                    }
                    2 -> {
                        mContext.startActivity<WindowManagerShowViewActivity>()
                    }
                    3 -> {
                        mContext.startActivity<RoomDataBaseUseActivity>()
                    }
                    4 -> {
                        mContext.startActivity<DrawBmpViewActivity>()
                    }
                    5 -> {
                        mContext.startActivity<WebViewPdfActivity>()
                    }
                    else -> {

                    }
                }
            }
        })
        val mLayoutManager = LinearLayoutManager(requireContext())
        mBinding.rvFloat.apply {
            layoutManager = mLayoutManager
            //layoutManager = LinearLayoutManager(context)
            adapter = mAdapter
            addItemDecoration(FloatItemDecoration(requireContext()))
        }
    }

    private fun testCoroutineStart() {
        launch(Dispatchers.Main) {
            //CoroutineStart.UNDISPATCHED:延续父协程所在的线程,直到遇到第一个挂起点,才切换到所设置的线程.
            /*launch(Dispatchers.IO, CoroutineStart.UNDISPATCHED) {
                Log.d(TAG,"thread0:${Thread.currentThread().name}")

                delay(1000)

                Log.d(TAG,"thread1:${Thread.currentThread().name}")
            }*/

            //CoroutineStart.DEFAULT:协程启动后,立即开始调度;遇到取消则立即进入取消状态.
            /*val job = launch(Dispatchers.IO, CoroutineStart.DEFAULT) {
                Log.d(TAG,"thread0:${Thread.currentThread().name}")

                delay(1000)

                Log.d(TAG,"thread1:${Thread.currentThread().name}")
            }
            job.start()
            delay(200)
            job.cancel()*/

            //CoroutineStart.ATOMIC:协程启动后,立即开始调度;遇到取消的话,直到遇到第一个挂起点才取消.
            /*val job = launch(Dispatchers.IO, CoroutineStart.ATOMIC) {
                delay(1000)
                Log.d(TAG,"thread0:${Thread.currentThread().name}")
                Log.d(TAG,"thread1:${Thread.currentThread().name}")
            }
            job.start()
            delay(200)
            job.cancel()*/

            //CoroutineStart.LAZY:调用start()/join()/await()方法时才会执行协程代码块中的逻辑;假如取消的话,将不会执行代码块逻辑.
            val job = launch(Dispatchers.Main, CoroutineStart.LAZY) {
                Log.d(TAG,"thread0:${Thread.currentThread().name}")
                delay(3000)
                Log.d(TAG,"thread1:${Thread.currentThread().name}")
            }
            job.start()
            delay(200)
            job.cancel()
        }
    }

    private fun testCoroutineDispatchers() {
        //Dispatchers.Unconfined:依赖父协程执行,前提是父协程的CoroutineDispatcher不是Dispatchers.Unconfined
        //优先于LiveData.observe执行
        launch(Dispatchers.Main) {
            val job = launch(Dispatchers.Unconfined) {
                Log.d(TAG,"Dispatchers---ABC---thread0:${Thread.currentThread().name}")
            }
        }

        //Dispatchers.Main:在主线中执行代码块逻辑,默认是Dispatchers.Main
        /*launch {
            Log.d(TAG,"Dispatchers---thread0:${Thread.currentThread().name}")
        }

        launch(Dispatchers.Main) {
            Log.d(TAG,"Dispatchers---thread0:${Thread.currentThread().name}")
        }*/

        //Dispatchers.IO:在子线程中执行逻辑
        /*launch(Dispatchers.IO) {
            Log.d(TAG,"Dispatchers---thread0:${Thread.currentThread().name}")
        }*/

        //Dispatchers.Default:在子线程中执行逻辑
        /*launch(Dispatchers.Default) {
            Log.d(TAG,"Dispatchers---thread0:${Thread.currentThread().name}")
        }*/
    }

    private fun testCoroutineScope() {
        //协程异常处理器
        val handler = CoroutineExceptionHandler { coroutineContext, throwable ->
            Log.d(TAG, "throwable:${throwable.javaClass.name}")
        }

        /*launch(handler) {
            coroutineScope {
                Log.d(TAG,"thread0:${Thread.currentThread().name}")
                val job1 = launch {
                    delay(200)
                    Log.d(TAG,"job1---job1---job1")
                }

                val job2 = launch {
                    delay(100)
                    Log.d(TAG,"job2---job2---job2")
                    throw IllegalArgumentException("非法参数异常")
                }
            }
        }*/

        /*launch(handler) {
            supervisorScope {
                Log.d(TAG,"thread0:${Thread.currentThread().name}")
                val job2 = launch {
                    delay(500)
                    Log.d(TAG,"job2---job2---job2")
                    throw IllegalArgumentException("非法参数异常")
                }

                val job1 = launch {
                    delay(1000)
                    Log.d(TAG,"job1---job1---job1")
                }
            }
        }*/

        val str = CoroutineScope(Dispatchers.Main + handler).launch {
            val job2 = launch {
                delay(100)
                Log.d(TAG,"job2---job2---job2")
                throw IllegalArgumentException("非法参数异常")
            }

            val job1 = launch {
                delay(600)
                Log.d(TAG,"job1---job1---job1")
            }
        }
    }

    private fun testCoroutineContext() {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
            Log.d(TAG, "Exception---${throwable.javaClass.simpleName}")
        }

        val job = launch(Dispatchers.Main + coroutineExceptionHandler) {
            Log.d(TAG, "job in job======888888")
        }

        //val supervisorJob = SupervisorJob()

        launch(Dispatchers.Main + job + CoroutineName("NewCoroutine") + coroutineExceptionHandler) {
            Log.d(TAG, "threadName:${Thread.currentThread().name}---main in main in main")
            throw IllegalArgumentException("非法参数异常")
        }
    }

    private fun testSupervisorJob() {
        val workerManager = DefineWorkerManager()
        workerManager.doWork1()
        workerManager.doWork2()
        workerManager.cancelWork()
        workerManager.doWork1()
    }

    class DefineWorkerManager {
        private val job = SupervisorJob()

        private val scope = CoroutineScope(Dispatchers.Main + job)

        fun doWork1() {
            scope.launch {
                Log.d(TAG, "doWork1()---doWork1()")
            }
        }

        fun doWork2() {
            scope.launch {
                Log.d(TAG, "doWork2()---doWork2()")
            }
        }

        fun cancelWork() {
            //job.cancel()
            scope.coroutineContext.cancelChildren()
        }
    }

    companion object {
        private const val TAG = "MineFragment"
        private const val KEY_PARAM = "mine"

        fun newInstance(param: String): MineFragment {
            val fragment = MineFragment()
            val bundle = Bundle()
            bundle.putString(KEY_PARAM, param)
            fragment.arguments = bundle
            return fragment
        }
    }
}